package com.jrx.anytxn.param.job.bactchBillCompare.config;

import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.common.uitl.FileUtils;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.config.BillCompareConfig;
import com.jrx.anytxn.param.config.PathFileConfig;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.TlThirdBillDetail;
import com.jrx.anytxn.param.entity.TlThirdBillSummary;
import com.jrx.anytxn.param.job.bactchBillCompare.bean.WexinFileNameBean;
import com.jrx.anytxn.param.mapper.ext.ExtTlBillTransCompareDetailMapper;
import com.jrx.anytxn.param.mapper.ext.ExtTlThirdBillDetailMapper;
import com.jrx.anytxn.param.mapper.ext.ExtTlThirdBillSummaryMapper;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 收单系统-微信还款账务文件入库job
 *
 * @author : chenjin
 * 2022/11/28
 */
@Configuration
@EnableConfigurationProperties(PathFileConfig.class)
public class WexinBillFileReadConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(WexinBillFileReadConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    private IOrganizationTableService organizationTableService;

    @Autowired
    private ISegmentService iSegmentService;

    @Resource
    private ExtTlThirdBillSummaryMapper extTlBillThirdSummaryMapper;

    @Resource
    private ExtTlThirdBillDetailMapper extTlBillThirdDetailMapper;

    @Resource
    private ExtTlBillTransCompareDetailMapper extTlBillTransCompareDetailMapper;

    @Autowired
    private BillCompareConfig billCompareConfig;

    // 还款
    private final String TRADE_CODE_HK = "1101";
    // 退货
    private final String TRADE_CODE_TH = "5151";

    @Bean
    public Job wexinBillFileReadJob() {
        return jobBuilderFactory.get("wexinBillFileReadJob")
                .start(wexinBillFileReadStep())
                .build();
    }

    @Bean
    public Step wexinBillFileReadStep() {
        return stepBuilderFactory.get("wexinBillFileReadStep")
                .tasklet(wexinBillFileReadTasklet())
                .build();
    }

    /**
     * 微信对账文件入库，若对账文件不存在，不受影响
     * @return
     */
    @Bean
    public Tasklet wexinBillFileReadTasklet() {
        return (contribution, chunkContext) -> {
            StopWatch sw = new StopWatch("文件读取耗时统计");

            PrOrganizationTable org = organizationTableService.findByOrgIdForBatch(Constant.XIB_ORG_NUMBER);
            // 设置指定对账日期
            Date today = billCompareConfig.getToday();
            if (Objects.nonNull(today)) {
                org.setToday(today);
            }

            // 参与目录路径计算的日期，yyyyMMdd
            String fileDate = DateUtils.format(org.getToday(), DateUtils.DATE_PATTERN_ANOTHER);

            // 系统业务日期，yyyy-MM-dd
            String businessDate = DateUtils.format(org.getToday());

            // 对账文件三方渠道号，由批次任务链参数传入
            String thirdChannel = billCompareConfig.getThirdChannel();

            // 指定日期的对账文件所在目录
            String path = WexinFileNameBean.directory(billCompareConfig.getFilePath(), thirdChannel, fileDate);
            logger.info("微信还款对账文件检查开始，渠道号:{} 业务日期为:{} 路径为:{} ", thirdChannel, businessDate, path);

            // 清理指定日期的渠道对账数据
            extTlBillThirdDetailMapper.deleteByBusDate(org.getToday(), thirdChannel);
            extTlBillThirdSummaryMapper.deleteByBusDate(org.getToday(), thirdChannel);

            List<TlThirdBillDetail> detailList = new LinkedList<>();
            List<File> files = FileUtils.findFiles(path);

            List<WexinFileNameBean> beans = FileUtils.findFiles(path).stream()
                    .map(File::getName)
                    .map(WexinFileNameBean::extract)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            for (WexinFileNameBean fileNameBean : beans) {
                logger.info("开始处理 : {}", fileNameBean.getFilename());
                sw.start(fileNameBean.getFilename());

                try(FileInputStream fis = new FileInputStream(Paths.get(path, fileNameBean.getFilename()).toFile());
                    InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
                    LineNumberReader reader = new LineNumberReader(isr)) {

                    String line = reader.readLine();
                    TlThirdBillSummary summary = this.buildBillSummary(fileNameBean, org, line);
                    if (summary == null) {
                        logger.error("微信还款对账，文件首行校验未通过。文件：{}", fileNameBean.getFilename());
                        continue;
                    }

                    // 文件第二行（含）之后，表示交易明细信息
                    while ((line = reader.readLine()) != null) {
                        logger.info("数据行 : {}", line);
                        if (0 == line.length()) {
                            logger.warn("存在为空的一行数据");
                            continue;
                        }

                        TlThirdBillDetail detail = buildBillDetail(fileNameBean, org, line);
                        if (detail == null) {
                            logger.error("行记录未成功解析");
                            continue;
                        }

                        detail.setId(iSegmentService.getId(Constant.TL_THIRD_BILL_DETAIL_TABLE));

                        // 根据明细，计算出汇总金额
                        compute(summary, detail);
                        detailList.add(detail);

                        if (detailList.size() == 5000) {
                            detailList.forEach(extTlBillThirdDetailMapper::insertSelective);
                            detailList.clear();
                        }
                    }

                    if (CollectionUtils.isNotEmpty(detailList)) {
                        detailList.forEach(extTlBillThirdDetailMapper::insertSelective);
                    }

                    summary.setId(iSegmentService.getId(Constant.TL_THIRD_BILL_SUMMARY_TABLE));
                    extTlBillThirdSummaryMapper.insertSelective(summary);
                }

                sw.stop();
                logger.info("交易流水文件读取结束 文件名:{}", fileNameBean.getFilename());
            }
            logger.info("交易流水文件读取完毕 业务日:{}  文件数量:{} 路径:{} \n {}", businessDate, files.size(), path, sw.prettyPrint());
            return RepeatStatus.FINISHED;
        };
    }

    /**
     * 初始化一个账单汇总实例
     * @param bean
     * @param org
     * @param line
     * @return
     * @throws SegmentException
     */
    private TlThirdBillSummary buildBillSummary(WexinFileNameBean bean, PrOrganizationTable org, String line) {
        boolean flag = true;
        String[] components = line.split("\\|");
        if (components.length < 5) {
            flag = false;
        } else {
            String busDate = DateUtils.parseStringDate(components[4], DateUtils.DATE_PATTERN_LINE, DateUtils.DATE_PATTERN_ANOTHER);// 日期
            flag = ObjectUtils.nullSafeEquals(components[2], bean.getMerchNo()) && ObjectUtils.nullSafeEquals(busDate, bean.getBusDate());
        }

        if (!flag) {
            return null;
        }

        TlThirdBillSummary summary = new TlThirdBillSummary();
        summary.setTenantId(org.getTenantId());
        summary.setOrganizationId(org.getOrganizationId());
        summary.setThirdChannel(billCompareConfig.getThirdChannel());
        summary.setBatchNumber("0000");
        summary.setBusinessDate(DateUtils.parseDate(bean.getBusDate(), DateUtils.DATE_PATTERN_ANOTHER));
        summary.setMerchNo(bean.getMerchNo());

        // 初始化其他默认值
        // 记录总值
        summary.setTotalCount(0);
        summary.setTotalAmount(BigDecimal.ZERO);

        // 消费，即微信还款
        summary.setConsumptionCount(0);
        summary.setConsumptionAmount(BigDecimal.ZERO);

        // 消费成功
        summary.setConsumptionSuccessCount(0);
        summary.setConsumptionSuccessAmount(BigDecimal.ZERO);

        // 退款，即微信还款成功后退货
        summary.setReturnCount(0);
        summary.setReturnAmount(BigDecimal.ZERO);

        // 退货成功
        summary.setReturnSuccessCount(0);
        summary.setReturnSuccessAmount(BigDecimal.ZERO);

        // 撤销
        summary.setRevokeCount(0);
        summary.setRevokeAmount(BigDecimal.ZERO);

        // 撤销成功
        summary.setRevokeSuccessCount(0);
        summary.setRevokeSuccessAmount(BigDecimal.ZERO);

        // 冲正
        summary.setRectificationCount(0);
        summary.setRectificationAmount(BigDecimal.ZERO);

        // 冲正成功
        summary.setRectificationSuccessCount(0);
        summary.setRectificationSuccessAmount(BigDecimal.ZERO);

        return summary;
    }

    /**
     * 初始化一个账单明细实例
     * @param bean
     * @param org
     * @param line
     * @return
     */
    private TlThirdBillDetail buildBillDetail(WexinFileNameBean bean, PrOrganizationTable org, String line) {
        TlThirdBillDetail detail = new TlThirdBillDetail();
        detail.setTenantId(org.getTenantId());
        detail.setOrganizationId(org.getOrganizationId());
        detail.setThirdChannel(billCompareConfig.getThirdChannel());
        detail.setBatchNumber("0000");

        String[] segs = line.trim().split("\\|");
        if (segs.length < 6) {
            return null;
        }

        if (StringUtils.isNotBlank(segs[3])) {
            detail.setThirdSeq(segs[3]);
        }

        detail.setBusinessDate(DateUtils.parseDate(bean.getBusDate(), DateUtils.DATE_PATTERN_ANOTHER));

        if (StringUtils.isNotBlank(segs[1])) {
            String s = DateUtils.format(detail.getBusinessDate(), DateUtils.DATE_PATTERN) + " " + segs[1];
            detail.setThirdTime(DateUtils.parseDate(s, DateUtils.DATETIME_PATTERN));
        }

        if (StringUtils.isNotBlank(segs[5])) {
            detail.setTransactionAmount(new BigDecimal(segs[5]));
        }

        String trade = segs[2];
        if (StringUtils.isNotBlank(trade)) {
            if (TRADE_CODE_HK.equals(trade)) {
                detail.setTransactionType(Constant.TRANSACTION_TYPE_WX_HK);
            } else if (TRADE_CODE_TH.equals(trade)) {
                detail.setTransactionType(Constant.TRANSACTION_TYPE_WX_TH);
            } else {
                logger.error("微信还款对账，文件：{}, 未知的交易类型：{}", bean.getFilename(), trade);
                return null;
            }
        }

        detail.setMerchNo(bean.getMerchNo());
        detail.setCompareFlag(Constant.COMPARE_FLAG_0);

        //新增字符赋值
        detail.setCoreSeq(detail.getThirdSeq());
        detail.setCoreBusDate(bean.getBusDate());

        // 对账文件中存在表明交易状态为成功
        detail.setTransStatus(Constant.TRANSACTION_STS_SUCCESS);
        return detail;
    }

    /**
     * 将明细聚合计算到汇总中
     * @param summary
     * @param detail
     */
    private void compute(TlThirdBillSummary summary, TlThirdBillDetail detail) {
        summary.setTotalCount(summary.getTotalCount() + 1);
        summary.setTotalAmount(summary.getTotalAmount().add(detail.getTransactionAmount()));

        // 消费
        if (ObjectUtils.nullSafeEquals(Constant.TRANSACTION_TYPE_WX_HK, detail.getTransactionType())) {
            summary.setConsumptionCount(summary.getConsumptionCount() + 1);
            summary.setConsumptionAmount(summary.getConsumptionAmount().add(detail.getTransactionAmount()));


        } else if (ObjectUtils.nullSafeEquals(Constant.TRANSACTION_TYPE_WX_TH, detail.getTransactionType())) {
            summary.setReturnCount(summary.getReturnCount() + 1);
            summary.setReturnAmount(summary.getReturnAmount().add(detail.getTransactionAmount()));
        }

        summary.setConsumptionSuccessCount(summary.getConsumptionCount());
        summary.setConsumptionSuccessAmount(summary.getConsumptionAmount());

        summary.setReturnSuccessCount(summary.getReturnCount());
        summary.setReturnSuccessAmount(summary.getReturnAmount());
    }



}